﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using UnityEngine;

namespace Zhongy
{
    public class ClientPer
    {
        public Socket ClientSocket { get; set; }
        public delegate void ReceiveCompleted(ClientPer client, SocketReceiveMsg msg);
        public ReceiveCompleted receiveCompleted;
        private  List<byte> dataCache = new List<byte>();
        public SocketAsyncEventArgs ReceiveArgs { get; set; }
        private bool isReceiveProcess = false;

        private int buffersize = 4096;

        public ClientPer()
        {
            this.ReceiveArgs = new SocketAsyncEventArgs();
            this.ReceiveArgs.UserToken = this;
            this.ReceiveArgs.SetBuffer(new byte[buffersize], 0, buffersize);
            this.SendArgs = new SocketAsyncEventArgs();
            this.SendArgs.Completed += send_Completed;
        }

        public void StartReceive(byte[] packet)
        {
            dataCache.AddRange(packet);

            if (!isReceiveProcess)
                processRecive();
        }

        private void processRecive()
        {
            isReceiveProcess = true;

            byte[] data = EncodeTool.DecodePacket(ref dataCache);

            //暂时剔除缓存功能
            dataCache.Clear();

            if (data == null)
            {
                isReceiveProcess = false;
                return;
            }

            List<SocketReceiveMsg> msgLst = EncodeTool.DecodeMsgs(data);

            //if (msgLst!=null)
            //Debug.LogError("msgLst.Count:" + msgLst.Count);
            //else
            //{
            //    Debug.LogError("msgLst is:" + "null");
            //    Debug.LogError("data.Length:" + data.Length);
            //}

            if (msgLst != null && msgLst.Count > 0)
            {
                for (int i = 0; i < msgLst.Count; i++)
                {
                    if (receiveCompleted != null)
                        if (msgLst[i] != null)
                            receiveCompleted(this, msgLst[i]);
                }
            }

            processRecive();

        }

        public void Disconnect()
        {
            dataCache.Clear();
            isReceiveProcess = false;

            sendQueue.Clear();
            isSendProcess = false;

            if (ClientSocket == null || !ClientSocket.Connected)
                return;

            Debug.Log("准备关闭:" + ClientSocket);

            try
            {
                ClientSocket.Shutdown(SocketShutdown.Both);
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
            }
            ClientSocket.Disconnect(false);

            // TODO 加上这两句会在tv上发生闪退
            //ClientSocket.Close();
            //ClientSocket = null;

        }

        private Queue<byte[]> sendQueue = new Queue<byte[]>();
        private bool isSendProcess = false;
        private SocketAsyncEventArgs SendArgs;
        public delegate void SendDisConnect(ClientPer client, string reason);
        public SendDisConnect sendDisConnect;

        public void Send(SocketSendMsg msg)
        {
            if (msg == null)
                Debug.LogError("udpmsg is null");

            byte[] data = EncodeTool.EncodeMsg(msg);

            //byte[] packet = EncodeTool.EncodePacket(data);

            Send(data);
        }

        public void Send(byte[] packet)
        {
            sendQueue.Enqueue(packet);
            if (!isSendProcess)
                send();
        }

        private void send()
        {
            isSendProcess = true;

            if (sendQueue.Count == 0)
            {
                isSendProcess = false;
                return;
            }

            byte[] packet = sendQueue.Dequeue();
            SendArgs.SetBuffer(packet, 0, packet.Length);

            bool result = ClientSocket.SendAsync(SendArgs);
            if (result == false)
            {
                processSend();
            }
        }

        private void send_Completed(object sender, SocketAsyncEventArgs e)
        {
            processSend();
        }

        private void processSend()
        {
            if (SendArgs.SocketError != SocketError.Success)
            {
                sendDisConnect(this, SendArgs.SocketError.ToString());
            }
            else
            {
                send();
            }
        }
    }
}
